1 /*
2 * Copyright (C) 2008 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.google.common.collect;
18
19 import com.google.common.annotations.GwtCompatible;
20
21 import java.util.Map;
22
23 /**
24 * An immutable {@link BiMap} with reliable user-specified iteration order. Does
25 * not permit null keys or values. An {@code ImmutableBiMap} and its inverse
26 * have the same iteration ordering.
27 *
28 * <p>An instance of {@code ImmutableBiMap} contains its own data and will
29 * <i>never</i> change. {@code ImmutableBiMap} is convenient for
30 * {@code public static final} maps ("constant maps") and also lets you easily
31 * make a "defensive copy" of a bimap provided to your class by a caller.
32 *
33 * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as
34 * it has no public or protected constructors. Thus, instances of this class are
35 * guaranteed to be immutable.
36 *
37 * @author Jared Levy
38 * @since 2.0 (imported from Google Collections Library)
39 */
40 @GwtCompatible(serializable = true, emulated = true)
41 public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V>
42 implements BiMap<K, V> {
43
44 /**
45 * Returns the empty bimap.
46 */
47 // Casting to any type is safe because the set will never hold any elements.
48 @SuppressWarnings("unchecked")
49 public static <K, V> ImmutableBiMap<K, V> of() {
50 return (ImmutableBiMap<K, V>) EmptyImmutableBiMap.INSTANCE;
51 }
52
53 /**
54 * Returns an immutable bimap containing a single entry.
55 */
56 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) {
57 return new SingletonImmutableBiMap<K, V>(k1, v1);
58 }
59
60 /**
61 * Returns an immutable map containing the given entries, in order.
62 *
63 * @throws IllegalArgumentException if duplicate keys or values are added
64 */
65 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2) {
66 return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2));
67 }
68
69 /**
70 * Returns an immutable map containing the given entries, in order.
71 *
72 * @throws IllegalArgumentException if duplicate keys or values are added
73 */
74 public static <K, V> ImmutableBiMap<K, V> of(
75 K k1, V v1, K k2, V v2, K k3, V v3) {
76 return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3));
77 }
78
79 /**
80 * Returns an immutable map containing the given entries, in order.
81 *
82 * @throws IllegalArgumentException if duplicate keys or values are added
83 */
84 public static <K, V> ImmutableBiMap<K, V> of(
85 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
86 return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3),
87 entryOf(k4, v4));
88 }
89
90 /**
91 * Returns an immutable map containing the given entries, in order.
92 *
93 * @throws IllegalArgumentException if duplicate keys or values are added
94 */
95 public static <K, V> ImmutableBiMap<K, V> of(
96 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
97 return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3),
98 entryOf(k4, v4), entryOf(k5, v5));
99 }
100
101 // looking for of() with > 5 entries? Use the builder instead.
102
103 /**
104 * Returns a new builder. The generated builder is equivalent to the builder
105 * created by the {@link Builder} constructor.
106 */
107 public static <K, V> Builder<K, V> builder() {
108 return new Builder<K, V>();
109 }
110
111 /**
112 * A builder for creating immutable bimap instances, especially {@code public
113 * static final} bimaps ("constant bimaps"). Example: <pre> {@code
114 *
115 * static final ImmutableBiMap<String, Integer> WORD_TO_INT =
116 * new ImmutableBiMap.Builder<String, Integer>()
117 * .put("one", 1)
118 * .put("two", 2)
119 * .put("three", 3)
120 * .build();}</pre>
121 *
122 * <p>For <i>small</i> immutable bimaps, the {@code ImmutableBiMap.of()} methods
123 * are even more convenient.
124 *
125 * <p>Builder instances can be reused - it is safe to call {@link #build}
126 * multiple times to build multiple bimaps in series. Each bimap is a superset
127 * of the bimaps created before it.
128 *
129 * @since 2.0 (imported from Google Collections Library)
130 */
131 public static final class Builder<K, V> extends ImmutableMap.Builder<K, V> {
132
133 /**
134 * Creates a new builder. The returned builder is equivalent to the builder
135 * generated by {@link ImmutableBiMap#builder}.
136 */
137 public Builder() {}
138
139 /**
140 * Associates {@code key} with {@code value} in the built bimap. Duplicate
141 * keys or values are not allowed, and will cause {@link #build} to fail.
142 */
143 @Override public Builder<K, V> put(K key, V value) {
144 super.put(key, value);
145 return this;
146 }
147
148 /**
149 * Associates all of the given map's keys and values in the built bimap.
150 * Duplicate keys or values are not allowed, and will cause {@link #build}
151 * to fail.
152 *
153 * @throws NullPointerException if any key or value in {@code map} is null
154 */
155 @Override public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
156 super.putAll(map);
157 return this;
158 }
159
160 /**
161 * Returns a newly-created immutable bimap.
162 *
163 * @throws IllegalArgumentException if duplicate keys or values were added
164 */
165 @Override public ImmutableBiMap<K, V> build() {
166 switch (size) {
167 case 0:
168 return of();
169 case 1:
170 return of(entries[0].getKey(), entries[0].getValue());
171 default:
172 return new RegularImmutableBiMap<K, V>(size, entries);
173 }
174 }
175 }
176
177 /**
178 * Returns an immutable bimap containing the same entries as {@code map}. If
179 * {@code map} somehow contains entries with duplicate keys (for example, if
180 * it is a {@code SortedMap} whose comparator is not <i>consistent with
181 * equals</i>), the results of this method are undefined.
182 *
183 * <p>Despite the method name, this method attempts to avoid actually copying
184 * the data when it is safe to do so. The exact circumstances under which a
185 * copy will or will not be performed are undocumented and subject to change.
186 *
187 * @throws IllegalArgumentException if two keys have the same value
188 * @throws NullPointerException if any key or value in {@code map} is null
189 */
190 public static <K, V> ImmutableBiMap<K, V> copyOf(
191 Map<? extends K, ? extends V> map) {
192 if (map instanceof ImmutableBiMap) {
193 @SuppressWarnings("unchecked") // safe since map is not writable
194 ImmutableBiMap<K, V> bimap = (ImmutableBiMap<K, V>) map;
195 // TODO(user): if we need to make a copy of a BiMap because the
196 // forward map is a view, don't make a copy of the non-view delegate map
197 if (!bimap.isPartialView()) {
198 return bimap;
199 }
200 }
201 Entry<?, ?>[] entries = map.entrySet().toArray(EMPTY_ENTRY_ARRAY);
202 switch (entries.length) {
203 case 0:
204 return of();
205 case 1:
206 @SuppressWarnings("unchecked") // safe covariant cast in this context
207 Entry<K, V> entry = (Entry<K, V>) entries[0];
208 return of(entry.getKey(), entry.getValue());
209 default:
210 return new RegularImmutableBiMap<K, V>(entries);
211 }
212 }
213
214 private static final Entry<?, ?>[] EMPTY_ENTRY_ARRAY = new Entry<?, ?>[0];
215
216 ImmutableBiMap() {}
217
218 /**
219 * {@inheritDoc}
220 *
221 * <p>The inverse of an {@code ImmutableBiMap} is another
222 * {@code ImmutableBiMap}.
223 */
224 @Override
225 public abstract ImmutableBiMap<V, K> inverse();
226
227 /**
228 * Returns an immutable set of the values in this map. The values are in the
229 * same order as the parameters used to build this map.
230 */
231 @Override public ImmutableSet<V> values() {
232 return inverse().keySet();
233 }
234
235 /**
236 * Guaranteed to throw an exception and leave the bimap unmodified.
237 *
238 * @throws UnsupportedOperationException always
239 * @deprecated Unsupported operation.
240 */
241 @Deprecated
242 @Override
243 public V forcePut(K key, V value) {
244 throw new UnsupportedOperationException();
245 }
246
247 /**
248 * Serialized type for all ImmutableBiMap instances. It captures the logical
249 * contents and they are reconstructed using public factory methods. This
250 * ensures that the implementation types remain as implementation details.
251 *
252 * Since the bimap is immutable, ImmutableBiMap doesn't require special logic
253 * for keeping the bimap and its inverse in sync during serialization, the way
254 * AbstractBiMap does.
255 */
256 private static class SerializedForm extends ImmutableMap.SerializedForm {
257 SerializedForm(ImmutableBiMap<?, ?> bimap) {
258 super(bimap);
259 }
260 @Override Object readResolve() {
261 Builder<Object, Object> builder = new Builder<Object, Object>();
262 return createMap(builder);
263 }
264 private static final long serialVersionUID = 0;
265 }
266
267 @Override Object writeReplace() {
268 return new SerializedForm(this);
269 }
270 }